/*
 * @Author:  WRay
 * @Date: 2021-10-16 17:21:07
 * @LastEditors:  WRay
 * @LastEditTime: 2021-11-09 16:29:36
 * @Description:
 * ===============+++++++++======================
 */
#include <iostream>
#include <opencv4/opencv2/opencv.hpp>
#include "R_CameraD.h"
#include "R_TestPID.h"

using namespace cv;
using namespace std;

Mat TestLoadImg();  //图像加载入口

int Test1();
int Test3();
int Test4();
int Test5();
int Test6();  //图像混合
int Test7();  //调整亮度与对比度

int Test8();  //绘制形状与文字
void MyLines();
void MyRectangle();
void MyEllipse();
void MyCircle();
void MyPolyygon();
void RadonLineDemo();

int Test9();   //模糊图像(均值/高斯)
int Test10();  //模糊（中值/双边）
int Test11();  //膨胀与腐蚀
void CallBack_Demo(int, void*);

int Test12();  //形态学操作

int main(int, char**)
{
  std::cout << "cv start!\n";
  int t_result = 0;

  //   t_result = Test1();
  //   t_result = Test3();
  //   t_result = Test4();
  //   t_result = Test5();
  //   t_result = Test6();
  // t_result = Test7();
  // t_result = Test8();
  // t_result = Test9();
  // t_result = Test10();
  // t_result = Test11();
  // t_result = Test12();

  /*****************TestPID*****************/
  R_TestPID* t_obj = new R_TestPID();
  R_CameraD* t_cd = new R_CameraD();
  return t_result;
}

Mat TestLoadImg()
{
  Mat result;
  result = imread("../soucre/corridor.jpg");
  return result;
}

int Test1()
{
  cv::Mat t_img = cv::imread("../soucre/corridor.jpg");

  if (t_img.empty())
  {
    printf("could not load mage... \n");
    return -1;
  }
  cv::namedWindow("cvT1", cv::WINDOW_AUTOSIZE);
  cv::imshow("cvT1", t_img);

  cv::namedWindow("cvT2", cv::WINDOW_AUTOSIZE);
  cv::Mat t_out;
  cv::cvtColor(t_img, t_out, cv::COLOR_BGR2GRAY);
  cv::imshow("cvT2", t_out);

  cv::imwrite("../soucre/corridor_gray.png", t_out);
  cv::waitKey(0);
  return 0;
}

int Test3()
{
  Mat t_src, t_dst;
  t_src = imread("../soucre/corridor.jpg");
  if (!t_src.data)
  {
    printf("could not load image ... \n");
    return -1;
  }

  String t_wname = "input show";
  namedWindow(t_wname, cv::WINDOW_AUTOSIZE);
  imshow(t_wname, t_src);

#if 0
  int cols = (t_src.cols - 1) * t_src.channels();
  int offsetx = t_src.channels();
  int rows = t_src.rows;
  t_dst = Mat::zeros(t_src.size(), t_src.type());
  for (int row = 1; row < (rows - 1); row++)
  {
    const uchar* previous = t_src.ptr<uchar>(row - 1);
    const uchar* current = t_src.ptr<uchar>(row);
    const uchar* next = t_src.ptr<uchar>(row + 1);
    uchar* output = t_dst.ptr<uchar>(row);
    for (int col = offsetx; col < cols; col++)
    {
      output[col] = saturate_cast<uchar>(5 * current[col] -
                                         (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
    }
  }
#endif

  double t = getTickCount();
  Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);  //定义掩模
  filter2D(t_src, t_dst, t_src.depth(), kernel);
  double timeconsume = (getTickCount() - t) / getTickFrequency();
  printf("Time consume %.3f \n", timeconsume);

  String t_name = "contract image";
  namedWindow(t_name, cv::WINDOW_AUTOSIZE);
  imshow(t_name, t_dst);
  waitKey(0);
}

int Test4()
{
  Mat src;
  src = imread("../soucre/corridor.jpg");
  if (src.empty())
  {
    cout << "could not load image ...\n" << endl;
    return -1;
  }

  String t_name = "InPut";
  namedWindow(t_name, cv::WINDOW_AUTOSIZE);
  imshow(t_name, src);

#if 0
  Mat dst;
  dst = Mat(src.size(), src.type());
  dst = Scalar(127, 0, 255);
  String t_name2 = "OutPut";
  namedWindow(t_name2, cv::WINDOW_AUTOSIZE);
  imshow(t_name2, dst);
#endif

  Mat dst;
  //   src.copyTo(dst);
  String t_name3 = "OutPut_3";
  namedWindow(t_name3, cv::WINDOW_AUTOSIZE);

  cvtColor(src, dst, cv::COLOR_BGRA2GRAY);
  printf("input image channels : %d \n", src.channels());
  printf("output image channels : %d \n", dst.channels());

  int cols = dst.cols;
  int rows = dst.rows;

  printf("rows : %d -- cols : %d  \n", rows, cols);
  const uchar* firstRow = dst.ptr<uchar>(0);
  printf("first pixel value : %d \n", *firstRow);
  //   imshow(t_name3, dst);

  Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));
  //   cout << "M = " << endl << M << endl;

  Mat m1;
  m1.create(src.size(), src.type());
  m1 = Scalar(0, 0, 255);
  //  imshow(t_name3, m1);

  Mat csrc;
  Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
  filter2D(src, csrc, -1, kernel);
  //   imshow(t_name3, csrc);

  //   Mat m2 = Mat::zeros(src.size(), src.type());

  // m2 =
  // [  0,   0;
  //    0,   0]
  Mat m2 = Mat::zeros(2, 2, CV_8UC1);
  cout << "m2 = " << endl << m2 << endl;

  // m2 =
  // [  1,   0;
  //    0,   1]
  //   Mat m2 = Mat::eye(2, 2, CV_8UC1);
  //   cout << "m2 = " << endl << m2 << endl;

  waitKey(0);
  return 0;
}

int Test5()
{
  Mat src, gray_src;
  src = imread("../soucre/corridor.jpg");
  if (src.empty())
  {
    cout << "could not load image ..." << endl;
    return -1;
  }

  String t_name = "InPut";
  namedWindow(t_name, cv::WINDOW_AUTOSIZE);
  imshow(t_name, src);

  cvtColor(src, gray_src, COLOR_BGRA2GRAY);
  String t_namt2 = "OutPut";
  namedWindow(t_namt2, cv::WINDOW_AUTOSIZE);
  imshow(t_namt2, gray_src);

  int height = gray_src.rows;
  int width = gray_src.cols;

  //单通道
  for (int row = 0; row < height; row++)
  {
    for (int col = 0; col < width; col++)
    {
      int gray = gray_src.at<uchar>(row, col);
      gray_src.at<uchar>(row, col) = 255 - gray;
    }
  }
  //   imshow(t_namt2, gray_src);

  //多通道

  Mat dst;
#if 1
  dst.create(src.size(), src.type());
  height = src.rows;
  width = src.cols;
  int nc = src.channels();

  for (int row = 0; row < height; row++)
  {
    for (int col = 0; col < width; col++)
    {
      if (nc == 1)
      {
        int gray = gray_src.at<uchar>(row, col);
        gray_src.at<uchar>(row, col) = 255 - gray;
      }
      else if (nc == 3)
      {
        int b = src.at<Vec3b>(row, col)[0];
        int g = src.at<Vec3b>(row, col)[1];
        int r = src.at<Vec3b>(row, col)[2];
        dst.at<Vec3b>(row, col)[0] = 255 - b;
        dst.at<Vec3b>(row, col)[1] = 255 - g;
        // dst.at<Vec3b>(row, col)[2] = 255 - r;
        dst.at<Vec3b>(row, col)[2] = 0;

        gray_src.at<uchar>(row, col) = max(r, max(b, g));
        gray_src.at<uchar>(row, col) = min(r, max(b, g));
      }
    }
  }
#endif
  //   bitwise_not(src, dst);
  //   imshow(t_namt2, dst);
  //   imshow(t_namt2, gray_src);

  waitKey(0);
  return 0;
}

int Test6()
{
  Mat src1, src2, dst;
  src1 = imread("../soucre/corridor.jpg");
  src2 = imread("../soucre/corridor.jpg");
  if (src1.empty())
  {
    cout << "src1 is empty ..." << endl;
    return -1;
  }
  if (src2.empty())
  {
    cout << "src2 is empty ..." << endl;
    return -1;
  }
  double alpha = 0.5;
  if (src1.rows == src2.rows && src1.cols == src2.cols && src1.type() == src2.type())
  {
    // addWeighted(src1, alpha, src2, 1 - alpha, 0, dst);
    // add(src1, src2, dst, Mat());
    multiply(src1, src2, dst, 1.0);

    imshow("src1", src1);
    imshow("src2", src2);
    namedWindow("Blend dst", cv::WINDOW_AUTOSIZE);
    imshow("Blend dst", dst);
  }
  else
  {
    printf("Could not blend images. \n");
    return -1;
  }

  waitKey(0);
  return 0;
}

/**
 * @description: 调整亮度与对比度
 * @param {*}
 * @return {*}
 */
int Test7()
{
  Mat src, dst;
  src = imread("../soucre/corridor.jpg");
  if (src.empty())
  {
    printf("src is empty ... \n");
    return -1;
  }
  char input_win[] = "Imput image";
  namedWindow(input_win, cv::WINDOW_AUTOSIZE);
  imshow(input_win, src);

  int height = src.rows;
  int width = src.cols;
  dst = Mat::zeros(src.size(), src.type());
  float alpha = 1.2;
  float beta = 10;

  Mat m1;
  // src.convertTo(m1, CV_32F);
  for (int row = 0; row < height; row++)
  {
    for (int col = 0; col < width; col++)
    {
      if (src.channels() == 3)
      {
        float b = src.at<Vec3b>(row, col)[0];
        float g = src.at<Vec3b>(row, col)[1];
        float r = src.at<Vec3b>(row, col)[2];

        dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b * alpha + beta);
        dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g * alpha + beta);
        dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r * alpha + beta);
      }
      else if (src.channels() == 1)
      {
        float v = src.at<uchar>(row, col);
        dst.at<uchar>(row, col) = saturate_cast<uchar>(v * alpha + beta);
      }
    }
  }

  char output_title[] = "contrast output";
  namedWindow(output_title, cv::WINDOW_AUTOSIZE);
  imshow(output_title, dst);

  waitKey(0);
  return 0;
}

/**
 * @description: 绘制形状与文字
 * @param {*}
 * @return {*}
 */
Mat bgImage;
const char* drawdemo_win = "draw shapes ahd text demo";
int Test8()
{
  bgImage = imread("../soucre/corridor.jpg");
  if (!bgImage.data)
  {
    printf("could not load image... \n");
    return -1;
  }

#if 0
  MyLines();
  MyRectangle();
  MyEllipse();
  MyCircle();
  MyPolyygon();

  putText(bgImage, "Find", Point(300, 300), QT_FONT_BLACK, 2, Scalar(12, 255, 200), 1, 8);

  namedWindow(drawdemo_win, cv::WINDOW_AUTOSIZE);
  imshow(drawdemo_win, bgImage);
#endif
  RadonLineDemo();

  waitKey(0);
  return 0;
}

void MyLines()
{
  Point p1 = Point(20, 30);
  Point p2;
  p2.x = 300;
  p2.y = 300;
  Scalar color = Scalar(0, 0, 255);
  line(bgImage, p1, p2, color, 1, LINE_8);
}

void MyRectangle()
{
  Rect rect = Rect(200, 100, 300, 300);
  Scalar color = Scalar(255, 0, 0);
  rectangle(bgImage, rect, color, 2, LINE_AA);
}

void MyEllipse()
{
  Scalar color = Scalar(0, 255, 0);
  ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 90, 0, 360,
          color, 2, LINE_8);
}

void MyCircle()
{
  Scalar color = Scalar(0, 255, 255);
  Point center = Point(bgImage.cols / 2, bgImage.rows / 2);
  circle(bgImage, center, 150, color, 2, 8);
}

void MyPolyygon()
{
  Point pts[1][5];
  pts[0][0] = Point(100, 100);
  pts[0][1] = Point(100, 200);
  pts[0][2] = Point(200, 200);
  pts[0][3] = Point(200, 100);
  pts[0][4] = Point(100, 100);

  const Point* ppts[] = { pts[0] };
  int npt[] = { 5 };
  Scalar color = Scalar(255, 12, 255);
  fillPoly(bgImage, ppts, npt, 1, color, 8);
}

void RadonLineDemo()
{
  RNG rng(123456);
  Point pt1;
  Point pt2;
  Mat bg = Mat::zeros(bgImage.size(), bgImage.type());
  namedWindow("random line demo", cv::WINDOW_AUTOSIZE);
  for (int i = 0; i < 100000; i++)
  {
    pt1.x = rng.uniform(0, bgImage.cols);
    pt2.x = rng.uniform(0, bgImage.cols);
    pt1.y = rng.uniform(0, bgImage.rows);
    pt2.y = rng.uniform(0, bgImage.rows);
    Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    if (waitKey(50) > 0)
    {
      break;
    }
    line(bg, pt1, pt2, color, 1, 8);
    imshow("random line demo", bg);
  }
}

int Test9()
{
  Mat src, dst;
  src = imread("../soucre/corridor.jpg");
  if (!src.data)
  {
    printf("could not load image... \n");
    return -1;
  }
  char input_title[] = "input image";
  char output_title[] = "outut image";
  namedWindow(input_title, WINDOW_AUTOSIZE);
  namedWindow(output_title, WINDOW_AUTOSIZE);

  imshow(input_title, src);
  blur(src, dst, Size(3, 3), Point(-1, -1));
  imshow(output_title, dst);

  Mat gblur;
  GaussianBlur(src, gblur, Size(5, 5), 11, 11);
  imshow("gaussian blur", gblur);

  waitKey(0);
  return 0;
}

int Test10()
{
  Mat src, dst;
  src = imread("../soucre/corridor.jpg");
  if (!src.data)
  {
    printf("could not load image... \n");
    return -1;
  }

  namedWindow("input", WINDOW_AUTOSIZE);
  imshow("input", src);

  // medianBlur(src, dst, 3);  //中值滤波
  bilateralFilter(src, dst, 15, 150, 5);  //双边滤波
  namedWindow("out medianBlur", WINDOW_AUTOSIZE);
  imshow("out medianBlur", dst);

  Mat gblur;
  GaussianBlur(src, gblur, Size(15, 15), 3, 3);
  imshow("gaus", gblur);

  Mat resultImg;
  Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
  filter2D(dst, resultImg, -1, kernel, Point(-1, -1), 0);
  imshow("Final Result", resultImg);

  waitKey(0);
  return 0;
}

char OUTPUT_WIN[] = "out img";
int element_size = 3;
int max_size = 21;
Mat src_11;
int Test11()
{
  Mat src = TestLoadImg();
  src_11 = src;
  namedWindow("input", WINDOW_AUTOSIZE);
  imshow("input", src);

  namedWindow(OUTPUT_WIN, WINDOW_AUTOSIZE);
  createTrackbar("Element Size :", OUTPUT_WIN, &element_size, max_size, CallBack_Demo);
  CallBack_Demo(0, 0);

  waitKey(0);
  return 0;
}

void CallBack_Demo(int, void*)
{
  Mat dst;
  int s = element_size * 2 + 1;
  Mat structuringElement = getStructuringElement(MORPH_RECT, Size(s, s), Point(-1, -1));
  // dilate(src_11, dst, structuringElement, Point(-1, -1)); //膨胀 =》 突出白色
  erode(src_11, dst, structuringElement);  //腐蚀  =》 突出黑色
  imshow(OUTPUT_WIN, dst);
}

int Test12()
{
  //-------------------开操作-------------------------
  //先腐蚀（去掉小白块，突出黑色），再膨胀（突出留下的白色块）
  Mat src = TestLoadImg();
}